from flask import current_app, g
from werkzeug.security import generate_password_hash, check_password_hash
import logging

from app.models.car import CarInfo
from common.utils.db import TotalNumberSerializer
from common.utils.jwt_util import create_token, check_token
from app import serializer
from marshmallow import (
    fields,
    Schema,
    validates,
    validates_schema,
    ValidationError,
    post_dump,
    post_load,
)

from app.models import db
from app.models.user import User, Role, PermissionPath


LOG = logging.getLogger(__name__)


class CarIdPutdSerializer(serializer.Schema):
    id = fields.Integer()
    create_time = fields.DateTime()
    car_num = fields.String()
    asset_code = fields.String()
    vin_num = fields.String()

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_car_info(self, data, many, **kwargs):
        car_id = data.pop("id")

        # 更新
        try:
            car_info = CarInfo.query.filter(CarInfo.id == car_id).update(data)
        except Exception as e:
            raise e

        db.session.commit()
        return car_info


class CarIdDeletedSerializer(serializer.Schema):
    id = fields.Integer()

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_car_info(self, data, many, **kwargs):
        # 删除
        try:
            car_info = CarInfo.query.get(data.get("id"))
        except Exception as e:
            raise e
        car_info.deleted = True
        db.session.commit()

        return car_info


class CarCreateQuerySerializer(serializer.Schema):
    create_time = fields.DateTime()
    car_num = fields.String()
    asset_code = fields.String()
    vin_num = fields.String()

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def create_car_info(self, data, many, **kwargs):
        # 保存
        car_info = CarInfo(**data)

        db.session.add(car_info)

        db.session.commit()

        return car_info


class CarListQuerySerializer(serializer.Schema):
    page = fields.Integer()
    per_page = fields.Integer()
    create_time = fields.DateTime()
    car_num = fields.String()
    asset_code = fields.String()
    vin_num = fields.String()

    @validates_schema
    def validates_data(self, data, **kwargs):
        pass

    @post_load
    def list_car_info(self, data, many, **kwargs):
        # 报存数据对象
        page = data.pop("page", 1)
        per_page = data.pop("per_page", 10)
        data["deleted"] = False
        car_infos = db.session.query(CarInfo).filter_by(**data).paginate(page, 100)
        return car_infos.items, car_infos.total


class CarIdSerializer(serializer.SQLAlchemySchema):
    class Meta:
        model = CarInfo
        fields = ["id"]


class CarBodySerializer(serializer.SQLAlchemySchema):
    class Meta:
        model = CarInfo
        fields = ["id", "car_num", "asset_code", "vin_num", "create_time"]


class CarDataSerializer(serializer.Schema, TotalNumberSerializer):
    data = fields.Nested(CarBodySerializer(many=True))


class PermissionPathSerializer(serializer.Schema):

    id = fields.Integer()
    path = fields.String()
    path_name = fields.String()
    icon = fields.String()


class RoleBodySerializer(serializer.Schema):
    path = fields.Nested(PermissionPathSerializer(many=True))
    id = fields.Integer()
    role_name = fields.String()


class UserBodySerializer(serializer.SQLAlchemySchema):
    roles = fields.Nested(RoleBodySerializer())

    class Meta:
        model = User
        fields = ["id", "username", "roles"]


class UserDataSerizlizer(serializer.SQLAlchemySchema, TotalNumberSerializer):
    data = fields.Nested(UserBodySerializer(many=True))


class UserInfoQuerySerializer(serializer.SQLAlchemySchema):
    class Meta:
        model = User
        fields = ["id"]

    @validates_schema
    def validate_username(self, data, **kwargs):
        """
        验证用户并返回user_obj
        """
        pass

    @post_load(pass_many=True)
    def get_users(self, data, many, **kwargs):

        # users = db.session.query(User).filter_by(**data).paginate(page, per_page)
        try:
            user = User.query.filter(User.id == data.get("id")).first()
        except Exception as e:
            raise e
        return user


class UserTokenSerizlizer(Schema):
    username = fields.Str()
    token = fields.Str()


class UserLoginQuerySerizlizer(Schema):
    username = fields.Str(required=True)
    password = fields.Str(required=True)

    @validates_schema
    def validates_data(self, data, **kwargs):
        try:
            self.user = User.query.filter_by(username=data.get("username")).first()
            LOG.error(self.user)
        except Exception as e:
            raise ValueError("用户名或密码错误")
        if not check_password_hash(self.user.password, data.get("password")):
            raise ValueError("用户名密码错误")

    @post_load
    def get_token(self, data, many, **kwargs):
        # 生成token
        data["token"] = create_token({"user_id": self.user.id})
        return data


class UserRegistrationBodySerializer(Schema):
    id = fields.Int()


class UserRegistrationQuerySerializer(Schema):
    username = fields.Str(required=True)
    password = fields.Str(required=True)
    password2 = fields.Str(required=True)
    role = fields.Str(required=True)

    @validates_schema
    def validate(self, data, **kwargs):
        if data.get("password") != data.get("password2") or data.get("username") == -1:
            raise RecursionError

    @post_load
    def save(self, data, many, **kwargs):
        # 通过了验证进行密码加密
        data["password"] = generate_password_hash(data.get("password"))
        try:
            role = Role.query.filter(Role.role_name == data.get("role")).first()
        except Exception as e:
            raise e
        user = User(username=data.get("username"), password=data.get("password"), role_id=role.id)

        db.session.add(user)
        db.session.commit()

        return user


class UpdateFiles(Schema):
    # 列表中的文件字段用fields.Function
    file = fields.List(fields.Function)
    name = fields.String()

    @validates_schema
    def validate(self, data, **kwargs):
        print(data)
